package Impl;

import Exceptions.PreCondException;
import Services.MoteurJeuService;
import Services.TerrainService;

public class MoteurJeu implements MoteurJeuService{//, RequireTerrainService {
	private TerrainService terrain;
	private boolean estFinie;
	private boolean estGagne;
	private boolean haveHeroMove;
	private boolean haveObjectMove;
	private int pasRestant;

	
	public MoteurJeu(){}
	
	public void init(int pasRestants, TerrainService terrain){
		if(! (pasRestants>0))
			throw new PreCondException("pre init");
		if(! terrain.isStarted())
			throw new PreCondException("pre init");
		
		this.estFinie = false;
		this.estGagne = false;
		this.pasRestant = pasRestants;
		this.haveHeroMove = false;
		this.haveObjectMove = false;
		this.terrain = terrain;
	}

	/*@Override
	public void bind(TerrainService terrain) {
		this.terrain = terrain;
	}*/

	@Override
	public boolean estFinie() {
		return estFinie;
	}

	@Override
	public boolean estGagne() {
		return estGagne;
	}

	@Override
	public int getPasRestants() {
		return pasRestant;
	}
	
	@Override
	public TerrainService getTerrain(){
		return terrain;
	}

	@Override
	public boolean haveObjectMove() {
		return haveObjectMove;
	}

	@Override
	public boolean haveHeroMove() {
		return haveHeroMove;
	}

	@Override
	public void moveHero(Dir direction){
		if(!(!estFinie)) 
			throw new PreCondException("pre movehero");
		if(!(!haveObjectMove)) 
			throw new PreCondException("pre movehero");
		if(!(!haveHeroMove)) 
			throw new PreCondException("pre movehero");
		
		int x = terrain.getXJoueur();
		int y = terrain.getYJoueur();
		haveHeroMove = true;
		
		Type type;
		switch(direction){
			case Haut:
				type = terrain.getTypeBloc(x, y-1);
				if(type==Type.SortieOuverte || type==Type.Terre || type==Type.Vide)
					terrain.putHero(x,y-1);
				break;
			case Bas:
				type = terrain.getTypeBloc(x, y+1);
				if(type==Type.SortieOuverte || type==Type.Terre || type==Type.Vide || type==Type.Diamant)
					terrain.putHero(x,y+1);
				break;
			case Droite:
				type = terrain.getTypeBloc(x+1, y);
				if(type==Type.SortieOuverte || type==Type.Terre || type==Type.Vide || type==Type.Diamant)
					terrain.putHero(x+1,y);
				else if(type==Type.Rocher && terrain.getTypeBloc(x+2,y)==Type.Vide){
					//terrain.moveObject(direction, x+1, y);
					terrain.moveObject(x+1, y, x+2, y);
					terrain.putHero(x+1,y);
				}
				break;
			case Gauche:
				type = terrain.getTypeBloc(x-1, y);
				if(type==Type.SortieOuverte || type==Type.Terre || type==Type.Vide || type==Type.Diamant)
					terrain.putHero(x-1,y);
				else if(type==Type.Rocher && terrain.getTypeBloc(x-2,y)==Type.Vide){
					//terrain.moveObject(direction, x-1, y);
					terrain.moveObject(x-1, y, x-2, y);
					terrain.putHero(x-1,y);
				}
				break;
			case Rien:
				break;
		}
		pasRestant--;
	}
	
	@Override
	public void moveObjects(){
		if(!(!estFinie)) 
			throw new PreCondException("pre moveObjects");
		if(!(haveHeroMove)) 
			throw new PreCondException("pre moveObjects");
		if(!(!haveObjectMove)) 
			throw new PreCondException("pre moveObjects");
		
		int sizeY = terrain.getSizeY();
		int sizeX = terrain.getSizeX();
		haveObjectMove = true;
		
		for(int y = sizeY; y>0; y--){
			for(int x = sizeX; x>0; x--){
				if(terrain.getTypeBloc(x, y)==Type.Rocher || terrain.getTypeBloc(x, y)==Type.Diamant)
					if(!terrain.isChanged(x, y) && (terrain.getTypeBloc(x, y+1)==Type.Vide || terrain.getTypeBloc(x, y+1)==Type.Hero))
						terrain.moveObject(x, y, x, y+1);
						//terrain.moveObject(Dir.Bas, x, y);
			}
		}
		
		terrain.validate();
	}
	
	@Override
	public void verif() {
		if(!(!estFinie)) 
			throw new PreCondException("pre verif");
		if(!(haveHeroMove)) 
			throw new PreCondException("pre verif");
		if(!(haveObjectMove)) 
			throw new PreCondException("pre verif");
		
		
		int x = terrain.getXJoueur();
		int y = terrain.getYJoueur();
		haveHeroMove = false;
		haveObjectMove = false;
		
		if(terrain.getNbDiamant()==0)
			terrain.openDoor();
		if(terrain.getTypeBloc(x, y)==Type.Rocher || terrain.getTypeBloc(x, y)==Type.Diamant){ // Joueur ecrase
			estFinie = true;
			estGagne = false;
		}
		if(terrain.getOldTypeBloc(x, y) == Type.SortieOuverte){ // Joueur sur la sortie
			estFinie = true;
			estGagne = true;
		}
		else if(getPasRestants() == 0){ // Pas restants nul
			estFinie = true;
			estGagne = false;
		}
	}
	
}
